package kp.rpc.loadbalancer.impl;

import kp.rpc.loadbalancer.LoadBalancer;
import kp.rpc.model.ServiceMetaInfo;

import java.util.List;
import java.util.Map;
import java.util.TreeMap;

/**
 * @author 86187
 * @description: 一致性hash算法
 * @date: 2024/6/7 13:11
 */

public class ConsistentHashLoadBalancer implements LoadBalancer {
    //一致性hash环
    private final TreeMap<Integer, ServiceMetaInfo> virtualNodeMap = new TreeMap<>();
    //虚拟节点数
    private static final int VIRTUAL_NODE_SIZE = 50;

    @Override
    public ServiceMetaInfo select(Map<String, Object> requestParams, List<ServiceMetaInfo> serviceMetaInfoList) {
        if (serviceMetaInfoList == null || serviceMetaInfoList.isEmpty() || requestParams == null) {
            return LoadBalancer.super.select(requestParams, serviceMetaInfoList);
        }
        //构建虚拟环节点
        serviceMetaInfoList.forEach(serviceMetaInfo -> {
            for (int i = 0; i < VIRTUAL_NODE_SIZE; i++) {
                String virtualNodeKey = serviceMetaInfo.getServiceKey() + "#" + i;
                virtualNodeMap.put(getHash(virtualNodeKey), serviceMetaInfo);
            }
        });
        //获取请求参数的hash值
        int hash = getHash(requestParams);
        //选择最接近且大于等于调用请求的hash值的虚拟节点
        Map.Entry<Integer, ServiceMetaInfo> integerServiceMetaInfoEntry = virtualNodeMap.ceilingEntry(hash);
        if (integerServiceMetaInfoEntry == null) {
            //如果找不到大于等于当前hash值的虚拟节点,就取第一个虚拟节点
            integerServiceMetaInfoEntry = virtualNodeMap.firstEntry();
        }
        return integerServiceMetaInfoEntry.getValue();
    }

    private int getHash(Object object) {
        return object.hashCode();
    }
}
